package css.sword.annotation;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import css.sword.annotation.kafka.OAKafkaBaseDao;
import css.sword.util.RedisDao;
import css.sword.util.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;


@Aspect
@Component
public class WebLogAspect {
    private Logger logger = LoggerFactory.getLogger(getClass().getName());
    private static final String DM_ZH_XTCS_KAFKA="List:CSB:CS_ZH_XTCS:all";
    private static final String DM_ZH_XTCS_KAFKA_OBJKEY="70D9AC7E2HJDCB89M0558L008H000J30";
    @Autowired
    RedisDao redisDao;

    @Pointcut("execution(public * css.sword.controller.*.*(..))")
//    @Pointcut("execution(public * css.sword.controller.*.*(..))"
//             +"|| execution(public * css.sword.service..*+.*(..))"
//             +"||  execution(* css.sword.mapper..*+.*(..))")
    public void webLog() {
    }

    //    @Before("webLog()")
    public void deBefore(JoinPoint joinPoint)  {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String sessionId = request.getSession().getId();
        Long startTime = System.currentTimeMillis();
        String url = request.getRequestURL().toString();
        String httpMethod = request.getMethod();
        String ip = request.getRemoteAddr();
        String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        //如果是表单，参数值是普通键值对。如果是application/json，则request.getParameter是取不到的。
        String headType = request.getHeader("Content-Type");
        logger.info("HTTP_HEAD Type : " + headType);
        logger.info("IP : " + ip);
        logger.info("CLASS_METHOD : " + classMethod);
        logger.info("HTTP_METHOD : " + httpMethod);
        // 记录下请求内容url
        logger.info("URL : " + url);
        logger.info("------开始时间---"+startTime);
        logger.info("------sessionId---"+sessionId);
        if ("application/json".equals(request.getHeader("Content-Type"))) {
            //记录application/json时的传参，SpringMVC中使用@RequestBody接收的值
            logger.info(getRequestPayload(request));
        } else {
            //记录请求的键值对
            for (String key : request.getParameterMap().keySet()) {
                logger.info(key + "----" + request.getParameter(key));
            }
        }
        Map<String,Object> soaMap = new HashMap<String,Object>();
        soaMap.put("sessionId",sessionId);
        soaMap.put("startTime",startTime.toString());
    }

//    @Around("webLog()")
    public Object Around(ProceedingJoinPoint proceedingJoinPoint){
        String strs = "";
//        Object[] paramValues = null;
        int flag = 0;
        Long end = 0L;
        Long msel= 0L;
        String reqData="";
        String resData="";
        Object result = null;
        String traceid = "";
        String topTraceId = "";
        String cldid = "";
        String hddyid = "";
        String fileSrcName = "";
        String md5Path = "";
        String fileSize = "";
        String ip = "";
        String identityId = "";
        String identityName = "";
        String deptId = "";
        String deptName = "";
        String jjdeptid = "";
        String jjdeptname = "";
        String wjbh = "";
        final Map<String, Object> map = new HashMap<String, Object>();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        Long start = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        reqData = getReqData(request);
        String serviceName = proceedingJoinPoint.getSignature().getDeclaringTypeName() + "." + proceedingJoinPoint.getSignature().getName();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String sessionId = request.getSession().getId();
        String requestUUid = String.valueOf(request.getSession().getAttribute(sessionId));
        String serverIp = WebAopTool.getLocalHostLANAddress();
        ip = getStr(request.getRemoteAddr());
        traceid = getStr(request.getParameter("traceid"));
        topTraceId = getStr(request.getParameter("toptraceid"));
        cldid = getStr(request.getParameter("cldid"));
        hddyid = getStr(request.getParameter("hddyid"));
        fileSrcName = getStr(request.getParameter("fileSrcName"));
        md5Path=request.getParameter("md5Path");
        if(StringUtils.isEmpty(md5Path) || "null".equals(md5Path)){
            md5Path=request.getParameter("md5");
        }
        md5Path = getStr(md5Path);
        fileSize = getStr(request.getParameter("fileSize"));
        identityId = getStr(request.getParameter("identityId"));
        wjbh = getStr(request.getParameter("wjbh"));
        if(null!=serviceName && serviceName.startsWith("css.sword.controller")) {
            requestUUid = UUID.randomUUID().toString().replace("-", "");
            request.getSession().setAttribute(sessionId, requestUUid);
        }
        WebAopTool.setAopStackParentServiceName(requestUUid, serviceName);
        String parentServiceName = WebAopTool.getParentServiceNameContainer(requestUUid);
        try {
            Map<String, Object> paramMap = getParam(identityId);
            identityName = String.valueOf(paramMap.get("identityName"));
            deptId = String.valueOf(paramMap.get("deptId"));
            if(!StringUtils.isEmpty(deptId)){
                deptName = getDeptnameBydeptId(deptId);
                Map<String, Object> deptInfo = getJjDeptMapByDeptId(deptId);
                if (null != deptInfo) {
                    jjdeptname = String.valueOf(deptInfo.get("deptname"));
                    jjdeptid = String.valueOf(deptInfo.get("sjdeptId"));
                }
            }
//      paramValues = proceedingJoinPoint.getArgs();
        }catch(Exception e){
            e.printStackTrace();
        }
        try {
            result = proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            strs = throwable.toString();
            flag = 1;
        } finally {
            try {
                if (result != null) {
                    resData = getResData(result);
                }
                end = System.currentTimeMillis();
                msel = end - start;
                map.put("wjbh",wjbh);
                map.put("flag", flag);
                map.put("ipdz", ip);
                map.put("serverip", serverIp);
                map.put("session_id", requestUUid);
                map.put("parent_session_id", requestUUid);
                map.put("servicename", serviceName);
                map.put("parent_servicename", getStr(parentServiceName));
                map.put("reqdata", reqData);
                map.put("resdata", resData);
                map.put("start_time", sf.format(start));
                map.put("end_time", sf.format(end));
                map.put("msel", msel);
                map.put("cldid",cldid);
                map.put("lrrq", sf.format(System.currentTimeMillis()));
                map.put("exception", strs);
                map.put("uuid", uuid);
                map.put("traceid", traceid);
                map.put("toptraceid", topTraceId);
                map.put("hddyid", hddyid);
                map.put("fileSrcName", fileSrcName);
                map.put("md5Path", md5Path);
                map.put("fileSize", fileSize);
                map.put("identity_id", identityId);
                map.put("identity_name", getStr(identityName));
                map.put("dept_id", getStr(deptId));
                map.put("dept_name", getStr(deptName));
                map.put("jjdeptid", getStr(jjdeptid));
                map.put("jjdeptname", getStr(jjdeptname));
                if (isEsOpen()) {
//                    logger.info("切面数据为："+map);
                    OAKafkaBaseDao kafkaBaseDao = new OAKafkaBaseDao();
                    kafkaBaseDao.sendkafka("soafile", map);
                }else{
                    logger.info("kafka已关闭:"+"topics=soafile,map:"+map);
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 公共方法，空串替换空值；
     * @param str
     * @return
     */
    public String getStr(String str){
       String a=str;
       if(StringUtils.isEmpty(a) || "null".equals(a)){
            a="";
       }
        return a;
    }

    /**
     *解析响应值
     * @param obj
     * @return
     */
    public String getResData(Object obj) {
        String str="未能解析";
        if(obj !=null){
            str = obj.toString();
        }else{
            str= "";
        }
        return str;
    }

    /**
     * 解析请求参数
     * @param request
     * @return
     */
    public String getReqData(HttpServletRequest request){
        String str = "未能解析";
        JSONObject jsb = new JSONObject();
        for (String key : request.getParameterMap().keySet()) {
            jsb.put(key,request.getParameter(key));
            str=jsb.toJSONString();
        }
        return str;
    }

    /**
     *获取identityName deptId
     * @param identityId
     * @return
     */
    public Map<String,Object> getParam(String identityId){
        String deptId="";
        String identityName = "";
        Map<String,Object> map=new HashMap<String,Object>();
        if (!StringUtils.isEmpty(identityId)) {
            Map<String,Object> deptMap = getIdentityNameAndDept(identityId);
            if(deptMap !=null){
                identityName = String.valueOf(deptMap.get("identityName"));
                deptId = String.valueOf(deptMap.get("deptId"));
                map.put("identityName",identityName);
                map.put("deptId",deptId);
            }
        }
        return map;
    }

    /**
     *查redis 获取identityName deptId
     * @param identityId
     * @return
     */
    public Map<String,Object> getIdentityNameAndDept(String identityId){
        Map<String,Object> deptMap=new HashMap<String,Object>();
        String deptId = "";
        String identityName = "";
        JSONObject userInfo = getMapCacheValueFromRedisByTableNameAndDmz("DM_GY_IDENTITY", identityId);
        if(userInfo != null && userInfo.size()!=0){
            identityName = userInfo.getString("IDENTITYNAME");
            deptId = userInfo.getString("DEPT_ID");
            deptMap.put("identityName",identityName);
            deptMap.put("deptId",deptId);
        }
        return deptMap;
    }

    /**
     *  记录application/json时的传参，SpringMVC中使用@RequestBody接收的值
     * @param req
     * @return
     */
    private String getRequestPayload(HttpServletRequest req) {
        StringBuilder sb = new StringBuilder();
        try(BufferedReader reader = req.getReader()) {
            char[]buff = new char[1024];
            int len;
            while((len = reader.read(buff)) != -1) {
                sb.append(buff,0, len);
            }
        }catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * kafka 开关
     * @return
     */
    public  boolean isEsOpen(){
        boolean isES = false;
        String esFlagValue  = redisDao.getString(DM_ZH_XTCS_KAFKA);
        if(null!=esFlagValue){
            JSONArray array = JSONObject.parseArray(esFlagValue);
            for (Object temobj:array) {
                Object cachValueObject =  JSONObject.toJSON(temobj);
                if(null!=cachValueObject){
                    JSONObject cacheJsonObject = JSONObject.parseObject(cachValueObject.toString());
                    if(null!= cacheJsonObject&&(DM_ZH_XTCS_KAFKA_OBJKEY.equals(String.valueOf(cacheJsonObject.get("CSBM"))))){
                        String CSZ = String.valueOf(cacheJsonObject.get("CSZ"));
                        if("Y".equals(CSZ)){
                            isES=true;
                        }
                        break;
                    }
                }
            }
        }
        return isES;
    }
    //DM_GY_IDEETITY
    public  JSONObject getMapCacheValueFromRedisByTableNameAndDmz(String tableName, String dmz)  {
        String fl = "";
        JSONObject resMap = new JSONObject();
        if (!StringUtils.isEmpty(tableName) && !StringUtils.isEmpty(dmz)) {
            if (tableName.startsWith("DM_")) {
                fl = "DMB";
            } else if (tableName.startsWith("CS_")) {
                fl = "CSB";
            }
            final String redisKey = "Map:" + fl + ":" + tableName.toUpperCase() + ":" + dmz;
            final String value = redisDao.getString(redisKey);
            if (StringUtils.isEmpty(value)) {
                logger.info("键为{}：在缓存中不存在该信息");
            } else {
                resMap = JSONObject.parseObject(value);
            }
            if (null == resMap) {
                if ("DM_GY_IDENTITY".equals(tableName)) {
                    resMap = new JSONObject();
                    resMap.put("IDENTITYNAME", dmz);
                } else {
                    resMap = new JSONObject();
                }
            }
        }
        return resMap;
    }

    /**
     * 根据部门id获取局级部门信息
     * @param deptId
     * @return
     */
    public  Map<String, Object> getJjDeptMapByDeptId(String deptId) {
        Map<String, Object> resMap = new HashMap<String, Object>();
        Map<String, Object> deptMap =getMapCacheValueFromRedisByTableNameAndDmz("DM_GY_DEPT", deptId);
        int i = 0;
        while (true) {
            i++;
            if (i > 10) {
                break;
            }
            if (null!=deptMap) {
                final String zzjgbz = (String) deptMap.get("ZZJGBZ");
                if ("1".equals(zzjgbz)) {
                    resMap = deptMap;
                    break;
                } else {
                    deptMap = getMapCacheValueFromRedisByTableNameAndDmz("DM_GY_DEPT", String.valueOf(deptMap.get("SJDEPT_ID")));
                }
            }
        }
        return getCusMapByCatchMap(resMap);
    }

    public  Map<String, Object> getCusMapByCatchMap(Map<String, Object> map)  {
        final Map<String, Object> resMap = new HashMap<String, Object>();
        if (null!=map) {
            final Iterator<String> keyIt = map.keySet().iterator();
            while (keyIt.hasNext()) {
                String key = keyIt.next();
                final Object value = (Object) map.get(key);
                key = conversStrToVoStytle(key);
                resMap.put(key, value);
            }
        }
        return resMap;
    }
    public static String conversStrToVoStytle(String str) {
        String tmp = str.toLowerCase();
        int ind = tmp.indexOf("_");
        while (ind >= 0) {
            tmp = tmp.substring(0, ind) + tmp.substring(ind + 1, ind + 2).toUpperCase() + tmp.substring(ind + 2);
            ind = tmp.indexOf("_");
        }
        return tmp;
    }
    public  String getDeptnameBydeptId(String deptId)  {
        String deptname = "";
        final Map<String, Object> deptMap = getMapCacheValueFromRedisByTableNameAndDmz("DM_GY_DEPT", deptId);
        if (null!=deptMap) {
            deptname = String.valueOf(deptMap.get("DEPTNAME"));
        }
        return deptname;
    }
}